package com.sbp.message.service.cs;

import com.dap.dao.model.Page;
import com.dap.utils.DateUtil;
import com.sbp.message.api.entity.Message;
import com.sbp.message.api.entity.MessageStatus;
import com.sbp.message.dao.IDaoService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
public class MessageCSImpl {
    private static final Logger logger = LoggerFactory.getLogger(MessageCSImpl.class);

    private static String formatErrorMessage(String errorMessage) {
        if (null != errorMessage && errorMessage.length() > 512) {
            return errorMessage.substring(0, 500) + "\n ...";
        } else {
            return errorMessage;
        }
    }
    private static String formatErrorLog(String errorLog) {
        return DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS") + " | " + errorLog;
    }


    @Autowired
    private IDaoService daoService;



    public Message insertMessage(Message message) {
        Date date = new Date();
        message.setCreateTime(date);
        message.setUpdateTime(date);

        daoService.insert(message);
        return message;
    }

    public int updateById(Message message) {
        message.updateTime = new Date();
        return daoService.updateById(message);
    }

    public int updateContentById(String id, String content) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("id", id);
        paramMap.put("content", content);
        paramMap.put("updateTime", new Date());
        return daoService.update(Message.class, "updateContentById", paramMap);
    }


    // 修改消息状态和错误日志
    public int updateMessageStatus(String messageId, MessageStatus messageStatus, String errorMessage, String errorLog) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("id", messageId);
        paramMap.put("status", messageStatus.getValue());
        paramMap.put("errorMessage", formatErrorMessage(errorMessage));
        paramMap.put("newErrorLog", formatErrorLog(errorLog));
        paramMap.put("updateTime", new Date());
        return daoService.update(Message.class, "updateStatusAndErrorLogById", paramMap);
    }
    // 修改错误日志
    public int updateErrorLogById(String messageId, String errorMessage, String errorLog) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("id", messageId);
        paramMap.put("errorMessage", formatErrorMessage(errorMessage));
        paramMap.put("newErrorLog", formatErrorLog(errorLog));
        paramMap.put("updateTime", new Date());
        return daoService.update(Message.class, "updateErrorLogById", paramMap);
    }

    public int confirmMessage(String messageId) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("id", messageId);
        paramMap.put("oldStatus", MessageStatus.unconfirmed.getValue());
        paramMap.put("newStatus", MessageStatus.confirmed.getValue());
        paramMap.put("updateTime", new Date());

        return daoService.update(Message.class, "updateStatusByIdAndStatus", paramMap);
    }
    public int updateUnconfirmedMessage(Message message) {
        return daoService.update(Message.class, "updateUnconfirmedMessage", message);
    }
    @Transactional
    public List<Message> confirmMessages(List<Message> messageList, MessageStatus targetStatus) {
        if (null == messageList || messageList.isEmpty())
            return new ArrayList<>();

        List<Message> result = new ArrayList<>();
        for (Message message : messageList) {
            message.setStatus(targetStatus.getValue());
            if (updateUnconfirmedMessage(message) > 0) {
                result.add(message);
            } else {
                logger.warn("messageId={}, confirm message failed", message.getId());
            }
        }
        return result;
    }

    public int deleteMessageById(String messageId) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("id", messageId);
        return daoService.delete(Message.class, "deleteMessageById", paramMap);
    }
    public int batchDelete(List<String> messageIdList) {
        return daoService.batchDelete(Message.class, messageIdList);
    }

    public int updateMessageWithConsumeSucceedById(String messageId, String newAcknowledgesDescribe) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("id", messageId);
        paramMap.put("newAcknowledgesDescribe", newAcknowledgesDescribe);
        paramMap.put("updateTime", new Date());
        return daoService.update(Message.class, "updateMessageWithConsumeSucceedById", paramMap);
    }
    public int updateMessageWithBusinessFailedById(String messageId, String newBusinessFailedDescribe) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("id", messageId);
        // 如果未消费, business_failed++, acknowledges_describe 追加 !appName!, 使用!! 来表示错误消费
        paramMap.put("newBusinessFailedDescribe", newBusinessFailedDescribe);
        paramMap.put("updateTime", new Date());
        return daoService.update(Message.class, "updateMessageWithBusinessFailedById", paramMap);
    }

    public int deleteMessageByIdIfAllAcknowledged(String messageId) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("id", messageId);
        return daoService.delete(Message.class, "deleteMessageByIdIfAllAcknowledged", paramMap);
    }
    public int endMessageByIdWithBusinessFailed(String messageId, MessageStatus messageStatus) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("id", messageId);
        paramMap.put("status", messageStatus.getValue());
        paramMap.put("updateTime", new Date());
        return daoService.update(Message.class, "endMessageByIdWithBusinessFailed", paramMap);
    }


    public int addSucceedUnexpectedConsumer(String messageId, String newSucceedUnexpectedConsumerDescribe) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("id", messageId);
        paramMap.put("newSucceedUnexpectedConsumerDescribe", newSucceedUnexpectedConsumerDescribe);
        paramMap.put("updateTime", new Date());
        return daoService.update(Message.class, "addSucceedUnexpectedConsumer", paramMap);
    }
    public int addFailedUnexpectedConsumer(String messageId, String newFailedUnexpectedConsumerDescribe, String errorLog) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("id", messageId);
        paramMap.put("newFailedUnexpectedConsumerDescribe", newFailedUnexpectedConsumerDescribe);
        paramMap.put("newErrorLog", formatErrorLog(errorLog));
        paramMap.put("updateTime", new Date());
        daoService.update(Message.class, "addFailedUnexpectedConsumer", paramMap);
        return 1;
    }


    public Message selectById(String msgId) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("id", msgId);
        return daoService.selectOne(Message.class, "selectById", paramMap);
    }

    public Message selectByIdAndStatus(String messageId, MessageStatus messageStatus) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("id", messageId);
        paramMap.put("status", messageStatus.getValue());
        return daoService.selectOne(Message.class, "selectOne", paramMap);
    }

    public List<Message> selectByIdsAndStatus(List<String> messageIdList, MessageStatus messageStatus) {
        Map<String, Object> paramMap = new HashMap<>();
        if (messageIdList != null)
            paramMap.put("idList", messageIdList);
        if (messageStatus != null)
            paramMap.put("status", messageStatus.getValue());
        return daoService.selectList(Message.class, "selectListByIdsAndStatus", paramMap);
    }


    public int removeMessages(List<String> msgIdList) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("list", msgIdList);
        return daoService.update(Message.class, "batchDelete", paramMap);
    }


    public Page<Message> queryMessageList(Map<String, Object> paramMap, Integer pageIndex, Integer pageSize) {
        return daoService.selectQueryResult(Message.class, "selectList", paramMap, pageIndex, pageSize);
    }

    public Page<Message> page(MessageStatus messageStatus, Integer pageIndex, Integer pageSize) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("status", messageStatus.getValue());
        return daoService.selectQueryResult(Message.class, "selectList", paramMap, pageIndex, pageSize);
    }

    public List<String> idPage(MessageStatus messageStatus, Integer pageIndex, Integer pageSize) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("status", messageStatus.getValue());
        paramMap.put("pageIndex", pageIndex);
        paramMap.put("pageSize", pageSize);
        return daoService.selectIdList(Message.class, "selectIdByStatus", paramMap);
    }


    public List<Message> selectShardingListByStatusAndElapseTime(
            MessageStatus messageStatus,
            int minElapseSeconds,
            int shardingItem, int shardingTotalCount) {
        // 根据当前所处的分片顺序,获取对应的消息数据
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("status", messageStatus.getValue());
        paramMap.put("maxTime", new Date(System.currentTimeMillis() - minElapseSeconds*1000L));
        paramMap.put("shardingItem", shardingItem);
        paramMap.put("shardingTotalCount", shardingTotalCount);
        return daoService.selectList(Message.class, "selectShardingListByStatusAndMaxTime", paramMap);
    }
}
